-- Utility function to tokenize a string into table values with char acting as a seperator between values
function TokenizeString(string,char)

	local temptable = { };
	local str = string;
	local s;
	while (s = strfind(str,char,1,true)) do
		tinsert(temptable,strsub(str,1,s-1));
		str = strsub(str,s+1);
	end

	return temptable;
	
end

Tactician_TempModuleData = { };
Tactician_PlayerSelectorList = nil;			-- Used by the player selector

Tactician_DataTransferQueue = { };

Tactician_TransferDataID = nil;
Tactician_TransferDataValue = nil;

function Tactician_ModuleEditorShow()

	Tactician_TempModuleData = { };
	local temptable;
	
	-- Copy the module data into a temporary table
	for k,v in pairs(Tactician_ModuleData) do
		temptable = {
			id = v.id,
			label = v.label,
			desc = v.desc,
			type = v.type,
			minValue = v.minValue,
			maxValue = v.maxValue,
			save = v.save			
		}
		if type(v.value) ~= "table" then
			temptable.value = v.value;
		else
			-- It's a table. Clone it.
			temptable.value = { };
			for k1,v1 in pairs(v.value) do
				tinsert(temptable.value,v1);
			end
		end
		tinsert(Tactician_TempModuleData,temptable);
	end
	
	Tactician_ModuleEditorUpdate();

end

function Tactician_ModuleEditorSave()
	
	local i;
	-- Save the temporary data into the actual table
	for i = 1, #Tactician_TempModuleData do
		Tactician_ModuleData[Tactician_TempModuleData[i].id] = Tactician_TempModuleData[i];
	end

end

function Tactician_ModuleEditorUpdate()

	FauxScrollFrame_Update(Tactician_ModuleEditorFrame_ScrollFrame,#Tactician_TempModuleData,8,51.2);
	
	local line, lineplusoffset, data, moduleData;
	
	for line=1,8 do
	    lineplusoffset = line + FauxScrollFrame_GetOffset(Tactician_ModuleEditorFrame_ScrollFrame);
		data = getglobal("Tactician_ModuleData"..line);
	    if lineplusoffset <= #Tactician_TempModuleData then
			moduleData = Tactician_TempModuleData[lineplusoffset];
			data.editing = lineplusoffset;
			-- Hide all controls
			getglobal(data:GetName().."_PlayerList"):Hide();
			getglobal(data:GetName().."_Check"):Hide();
			getglobal(data:GetName().."_Slider"):Hide();
			getglobal(data:GetName().."_PlayerButton"):Hide();
			getglobal(data:GetName().."_EditBox"):Hide();
			if (moduleData.type == "text") then
				-- Show the edit box
				getglobal(data:GetName().."_EditBox"):SetText(moduleData.value);
				getglobal(data:GetName().."_EditBox"):Show();
			elseif (moduleData.type == "integer") then
				-- Show the slider
				getglobal(data:GetName().."_Slider"):SetMinMaxValues(moduleData.minValue,moduleData.maxValue);
				getglobal(data:GetName().."_Slider"):SetValue(moduleData.value);
				getglobal(data:GetName().."_Slider"):Show();
			elseif (moduleData.type == "boolean") then
				-- Show the check
				getglobal(data:GetName().."_Check"):SetChecked(moduleData.value);
				getglobal(data:GetName().."_Check"):Show();
			elseif (moduleData.type == "playerlist") then
				-- Show the player list
				getglobal(data:GetName().."_PlayerButton"):Show();
				getglobal(data:GetName().."_PlayerList"):Show();
				local s = "";
				for k,v in pairs(moduleData.value) do
					s = s .. v .. " ";
				end
				getglobal(data:GetName().."_PlayerList"):SetText(s);
			end
			-- Update the labels
			getglobal(data:GetName().."_Label"):SetText(moduleData.label);
			getglobal(data:GetName().."_Description"):SetText(moduleData.desc);
			data:Show();
	    else
			data:Hide();		
	    end
	end
	
end

-- Show the player selector, with editing being the index of the data being edited.
function Tactician_ShowPlayerSelector(editing)

	Tactician_PlayerSelectFrame.editing = editing;
	
	Tactician_PlayerSelectorList = { };
	
	-- First we run each player through the filter. If ok, we add it to the table
	local i,x,y;
	local unit,name,class,group;
	local temptable;
	for i = 1,GetNumRaidMembers() do
		unit = "raid"..i;
		if (Tactician_TempModuleData[editing].filter) then
			-- There is a filter. So pass the unit to the filter.
			if (Tactician_TempModuleData[editing].filter(unit)) then
				-- It passed so add the unit.
				temptable = { name = UnitName(unit) }
				-- We need to get the group number now
				for x = 1,40 do
					name,_,group,_,class = GetRaidRosterInfo(i);
					if (name) then
						if (name == UnitName(unit)) then
							-- This is the player we're looking for
							temptable.group = group;
							temptable.class = class;
							break;
						end
					end
				end
				-- Check to see if this unit is selected.
				temptable.selected = nil;
				for x = 1,#Tactician_TempModuleData[editing].value do
					if (Tactician_TempModuleData[editing].value[x] == UnitName(unit)) then
						-- This player is selected.
						temptable.selected = 1;
					end
				end
				tinsert(Tactician_PlayerSelectorList,temptable);
			end
		else
			-- No filter. Add all the units.
			temptable = { name = UnitName(unit) };
			-- We need to get the group number now
			for x = 1,40 do
				name,_,group,_,_,class = GetRaidRosterInfo(i);
				if (name) then
					if (name == UnitName(unit)) then
						-- This is the player we're looking for
						temptable.group = group;
						temptable.class = class;
						break;
					end
				end
			end
			-- Check to see if this unit is selected.
			temptable.selected = nil;
			for x = 1,#Tactician_TempModuleData[editing].value do
				if (Tactician_TempModuleData[editing].value[x] == UnitName(unit)) then
					-- This player is selected.
					temptable.selected = 1;
				end
			end
			tinsert(Tactician_PlayerSelectorList,temptable);
		end
	end
	
	Tactician_PlayerSelectFrame:Show();

end

-- Updates the player selector frame
function Tactician_PlayerSelectUpdate()

	FauxScrollFrame_Update(Tactician_PlayerSelectFrame_ScrollFrame,#Tactician_PlayerSelectorList,6,25);

	local line, lineplusoffset, select, playerSelect;
	
	for line=1,6 do
	    lineplusoffset = line + FauxScrollFrame_GetOffset(Tactician_PlayerSelectFrame_ScrollFrame);
		select = getglobal("Tactician_PlayerSelect"..line);
	    if lineplusoffset <= #Tactician_PlayerSelectorList then
			playerSelect = Tactician_PlayerSelectorList[lineplusoffset];
			select.editing = lineplusoffset;
			if (playerSelect.selected) then
				-- It's selected. Highlight this.
				select:LockHighlight();
			else
				select:UnlockHighlight();
			end
			getglobal(select:GetName().."_Name"):SetText(playerSelect.name);
			getglobal(select:GetName().."_Name"):SetTextColor(RAID_CLASS_COLORS[playerSelect.class].r,RAID_CLASS_COLORS[playerSelect.class].g,RAID_CLASS_COLORS[playerSelect.class].b);
			getglobal(select:GetName().."_Group"):SetText(playerSelect.group);
			select:Show();
	    else
			select:Hide();
	    end
	end
	
end

-- Save as in transfer the selection to the TempData
function Tactician_SavePlayerSelection()
	
	local temptable = { };
	for i = 1, #Tactician_PlayerSelectorList do
		if (Tactician_PlayerSelectorList[i].selected) then
			tinsert(temptable,Tactician_PlayerSelectorList[i].name);
		end
	end
	
	-- Now transfer it to the values
	Tactician_TempModuleData[Tactician_PlayerSelectFrame.editing].value = temptable;
	
	Tactician_ModuleEditorUpdate();
	
end

-- Starts a data transmit to every other raid member. Only the raid leader can do this.
-- (And even if you hack this, the other clients will check that the message is coming from the raid leader anyway... so, ha!)
function Tactician_TransmitModuleData()

	if (not IsRaidLeader()) then
		DEFAULT_CHAT_FRAME:AddMessage("Tactician: Only raid leaders can transmit module data."
		return;
	end
	
	-- First, initiate the data transfer by clearing the transfer table
	Tactician_DataTransferQueue = { };

	-- Now, take every ModuleData item and add its ID and value to the transfer table.
	-- Anything else isn't needed.
	local temptable;
	
	for k,v in pairs(Tactician_ModuleData) do
		temptable = { id = v.id, value = v.value };
		tinsert(Tactician_DataTransferQueue,temptable);
	end
	
	-- Send the initiatory addon message sending the id of the module to update.
	SendAddonMessage("TACTI_DATAINIT",Tactician_LoadedModule,"RAID");
	
	-- Activate the DataTransfer frame
	Tactician_DataTransferFrame:Show();
	
	-- Let the transfer frame do it's magic.
	
end

-- The update handler for the transfer frame.
function Tactician_DataTransferUpdate()

	if (not Tactician_DataTransferQueue[1]) then
		-- The transfer queue has finished. End the transfer.
		SendAddonMessage("TACTI_DATAEND",Tactician_LoadedModule,"RAID");
	end
	
	-- Data will be sent using two messages.
	
	-- The first message contains the id for the data.
	-- The second message will contain the value for the data. (EXCEPT FOR TABLE DATA!)
	local data = Tactician_DataTransferQueue[1];
	
	SendAddonMessage("TACTI_DATAID",data.id,"RAID");
	if (type(data.value) ~= "table") then
		SendAddonMessage("TACTI_DATAVAL",data.value,"RAID");
	else
		-- It's a table. We need to expand the table, delimited using the ?
		local s = "";
		for k,v in pairs(data.value) do
			s = s .. v .. "?";
		end
		SendAddonMessage("TACTI_DATAVAL",s,"RAID");
	end
	
	-- Once this data's transfer is complete, remove it for the queue so that data transfer can continue
	tremove(Tactician_DataTransferQueue,1);

end

-- This handler handles DataTransfer messages
function Tactician_HandleDataTransfer()

	local prefix, msg, channel, author = arg1, arg2, arg3, arg4;
	local i;
	local ok = false;
	
	-- DataTransfer messages can only come from the raid leader.
	for i = 1, 40 do
		name,rank = GetRaidRosterInfo(i);
		if (name) and (name == author) then
			if (rank == 2) then
				-- It's the raid leader
				ok = true;
				break;
			end
		end
	end
	
	if (not ok) then
		-- Someone hacked his version. Ignore the message.
		return;
	end
	
	if (prefix == "TACTI_DATAID") then
		-- Sending us the data id. Store it for when we receive the value.
		Tactician_TransferDataID = msg;
	elseif (prefix == "TACTI_DATAVAL") then
		-- Check to see whether the data we have is a table value.
		if (not Tactician_TransferDataID) then
			-- Someone hacked his version. Ignore the message.
			return;
		end
		if (Tactician_ModuleData[Tactician_TransferDataID].type == "playerlist") then
			-- Table value.
			Tactician_ModuleData[Tactician_TransferDataID].value = TokenizeString(msg,"?");						
		else
			-- Normal value.
			Tactician_ModuleData[Tactician_TransferDataID].value = msg;
		end
	end

end